import {
    PayableOverrides,
    BigNumber ,
    BigNumberish,
    Overrides,
    CallOverrides,
    BytesLike,
    providers
} from 'ethers';
import { IArrtibuteClient } from './IArrtibute-client';
import { EtherERC721Client } from './ethers-ERC721-client';
import { ArrtibuteAssert, ArrtibuteAssert__factory } from '../../types';

export class EtherArrtibuteClient extends  EtherERC721Client implements IArrtibuteClient{
    public arrtibuteAssert: ArrtibuteAssert | undefined;//typechain 合约

    public connectProvider(address: string, provider: providers.Provider){
        super.connectProvider(address,provider);
        this.provider = provider;
        this.arrtibuteAssert = ArrtibuteAssert__factory.connect(address,this.provider);

    }

    public contract(): Promise<ArrtibuteAssert> {
        if (this.provider === undefined || this.arrtibuteAssert === undefined) {
          return Promise.reject('need to connect a valid provider');
        }
        return Promise.resolve(this.arrtibuteAssert);
    }

    public getArtist(config?: CallOverrides): Promise<string>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.getArtist({...config});
    }

    public getArtwork_image_uri(config?: CallOverrides): Promise<string>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.getArtwork_image_uri({...config});
    }

    public getArtwork_metadata_uri(config?: CallOverrides): Promise<string>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.getArtwork_metadata_uri({...config});
    }

    public getArtwork_name(config?: CallOverrides): Promise<string>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.getArtwork_name({...config});
    }

    public getCurrentIssue(config?: CallOverrides): Promise<BigNumber>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.getCurrentIssue({...config});
    }

    public getNextTokenId(config?: CallOverrides): Promise<BigNumber>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.getNextTokenId({...config});
    }

    getTotalIssue(config?: CallOverrides): Promise<BigNumber>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.getTotalIssue({...config});
    }

    public get_AssertIndex(config?: CallOverrides): Promise<BigNumber>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.get_AssertIndex({...config});
    }

    public get_trait_type(config?: CallOverrides): Promise<number>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.get_trait_type({...config});
    }



    public name(config?: CallOverrides): Promise<string>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.arrtibuteAssert.name({...config});
    }

    public owner(config?: CallOverrides): Promise<string>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined 
        ){
            return Promise.reject('need to connect a valid provider');
        }

        return this.owner({...config});
    }

    public async safeMint(
    to: string,
    config?: Overrides & { from?: string | Promise<string> }
    ): Promise<any> {
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        const gas = await this.arrtibuteAssert
        .connect(this.signer)
        .estimateGas.safeMint(to ,{...config});


        const transaction = await this.arrtibuteAssert
        .connect(this.signer)
        .safeMint(to,{ gasLimit: gas.mul(13).div(10), ...config });
        
        const receipt = await transaction.wait(this._waitConfirmations);
        return receipt
    }

    // "safeTransferFrom(address,address,uint256)"(
    // from: string,
    // to: string,
    // tokenId: BigNumberish,
    // overrides?: Overrides & { from?: string | Promise<string> }
    // ): Promise<any>;

    // "safeTransferFrom(address,address,uint256,bytes)"(
    // from: string,
    // to: string,
    // tokenId: BigNumberish,
    // _data: BytesLike,
    // overrides?: Overrides & { from?: string | Promise<string> }
    // ): Promise<any>;

    public async setTokenURI(
        tokenId: BigNumberish,
        uri: string,
        config?: Overrides & { from?: string | Promise<string> }
    ): Promise<any>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        const gas = await this.arrtibuteAssert
        .connect(this.signer)
        .estimateGas.setTokenURI(tokenId,uri ,{...config});


        const transaction = await this.arrtibuteAssert
        .connect(this.signer)
        .setTokenURI(tokenId,uri ,{ gasLimit: gas.mul(13).div(10), ...config });
        
        const receipt = await transaction.wait(this._waitConfirmations);
        return receipt
    }

    public supportsInterface(
    interfaceId: BytesLike,
    overrides?: CallOverrides
    ): Promise<boolean>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        return this.supportsInterface(interfaceId,{...overrides});
    }

    public symbol(overrides?: CallOverrides): Promise<string>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        return this.symbol({...overrides});
    }

    public tokenIdExist(
    tokenid: BigNumberish,
    overrides?: CallOverrides
    ): Promise<boolean>{
        if (
            this.provider === undefined ||
            this.arrtibuteAssert === undefined ||
            this.signer === undefined
        ){
            return Promise.reject('need to connect a valid provider and signer');
        }

        return this.tokenIdExist(tokenid , {...overrides});
    }


    // lockToken(
    //     tokenId: BigNumberish,
    //     caller: string,
    //     overrides?: Overrides & { from?: string | Promise<string> }
    //     ): Promise<any>;


    //   unlockToken(
    //     tokenId: BigNumberish,
    //     caller: string,
    //     overrides?: Overrides & { from?: string | Promise<string> }
    //   ): Promise<any>;
}